﻿using Library.Common.Model;
using Library.Core.Application.IInfrastructure;
using Library.Core.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace Library.Core.Application.BaseAction
{
    public abstract class BaseService<Tin, TOut> where Tin : class, new()
    {
        private readonly ILogger<BaseService<Tin, TOut>> logger;
        private readonly ICustomModelValidator modelValidator;
        public BaseService(IIocContainer container)
        {
            logger = container.Resolve<ILogger<BaseService<Tin, TOut>>>();
            modelValidator = container.Resolve<ICustomModelValidator>();
        }
        public abstract Task<BaseApiResult<TOut>> Query(Tin input);

        public BaseApiResult<Tout> Handle<Tout>(Func<Tout> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }
        public BaseApiResult<Tout> Handle<Tout>(Tin input, Func<Tout> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        /// <summary>
        /// 无参数
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<Tout>> HandleAsync<Tout>(Func<Task<Tout>> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = await func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        /// <summary>
        /// 无参数，多了一个catchfunc
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="func"></param>
        /// <param name="catchfunc"></param>
        /// <returns></returns>
        public BaseApiResult<Tout> Handle<Tout>(Func<Tout> func, Func<Exception, Task> catchfunc = null)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
                try
                {
                    catchfunc?.Invoke(e);
                }
                catch (Exception) { }
            }
            return result;
        }

        /// <summary>
        /// 有参数验证
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="input"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<Tout>> HandleAsync<Tout>(Tin input, Func<Task<Tout>> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = await func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        /// <summary>
        /// 有参数验证+catchfunc
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="input"></param>
        /// <param name="func"></param>
        /// <param name="catchfunc"></param>
        /// <returns></returns>
        public BaseApiResult<Tout> Handle<Tout>(Tin input, Func<Tout> func, Func<Exception, Task> catchfunc = null)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
                try
                {
                    catchfunc?.Invoke(e);
                }
                catch (Exception) { }
            }
            return result;
        }

        /// <summary>
        /// 验证参数
        /// </summary>
        /// <param name="input"></param>
        void ValidParm(Tin input)
        {
            var validResults = modelValidator.Valid(input);
            if (validResults.Count > 0)
            {
                throw new ApplicationsException(validResults[0].ErrorMessage);
            }
        }

        /// <summary>
        /// 错误处理
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="result"></param>
        /// <param name="e"></param>
        private void ExHandler<Tout>(BaseApiResult<Tout> result, Exception e)
        {
            if (e is CustomerException)
            {
                result.Code = ((CustomerException)e).Code;
                result.ErrMessage = e.Message;
            }
            else if (e is DbUpdateConcurrencyException)
            {
                result.Code = (int)CustomError.InvalidOperation;
                result.ErrMessage = "该数据已被别人修改,请重试！";
            }
            else
            {
                logger.LogError(e, e.Message);
                result.Code = (int)CustomError.InvalidOperation;
                result.ErrMessage = "出错了,请稍后再试";
            }
        }
    }

    /// <summary>
    /// 无参数
    /// </summary>
    public abstract class BaseService
    {
        private readonly ILogger<BaseService> logger;
        private readonly ICustomModelValidator modelValidator;
        public BaseService(IIocContainer container)
        {
            logger = container.Resolve<ILogger<BaseService>>();
            modelValidator = container.Resolve<ICustomModelValidator>();
        }

        public BaseApiResult<Tout> Handle<Tout>(Func<Tout> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        public BaseApiResult<Tout> Handle<Tout>(Func<Tout> func, Func<Exception, Task> catchfunc = null)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = func();
                result.Code = 0;
            }
            catch (Exception e)
            {
                ExHandler(result, e);
                try
                {
                    catchfunc?.Invoke(e);
                }
                catch (Exception) { }
            }
            return result;
        }

        public BaseApiResult<Tout> Handle<Tout, Tin>(Tin input, Func<Tout> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        public BaseApiResult<Tout> Handle<Tout, T>(T input, Func<Tout> func, Func<Exception, Task> catchfunc = null)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
                try
                {
                    catchfunc?.Invoke(e);
                }
                catch (Exception) { }
            }
            return result;
        }

        public async Task<BaseApiResult<Tout>> HandleAsync<Tout>(Func<Task<Tout>> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = await func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        public async Task<BaseApiResult<Tout>> HandleAsync<Tout>(Func<Task<Tout>> func, Func<Exception, Task> catchfunc = null)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                result.Data = await func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
                try
                {
                    catchfunc?.Invoke(e);
                }
                catch (Exception) { }
            }
            return result;
        }

        public async Task<BaseApiResult<Tout>> HandleAsync<Tout, Tin>(Tin input, Func<Task<Tout>> func)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = await func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
            }
            return result;
        }

        public async Task<BaseApiResult<Tout>> HandleAsync<Tout, T>(T input, Func<Task<Tout>> func, Func<Exception, Task> catchfunc = null)
        {
            var result = new BaseApiResult<Tout>();
            try
            {
                ValidParm(input);
                result.Data = await func();
            }
            catch (Exception e)
            {
                ExHandler(result, e);
                try
                {
                    catchfunc?.Invoke(e);
                }
                catch (Exception) { }
            }
            return result;
        }

        void ValidParm<Tin>(Tin input)
        {
          
            var validResults = modelValidator.Valid(input);
            if (validResults.Count > 0)
            {
                throw new ApplicationsException(validResults[0].ErrorMessage);
            }
        }

        private void ExHandler<Tout>(BaseApiResult<Tout> result, Exception e)
        {
            if (e is CustomerException)
            {
                result.Code = ((CustomerException)e).Code;
                result.ErrMessage = e.Message;
                result.Msg = e.Message;
            }
            else if (e is DbUpdateConcurrencyException)
            {
                result.Code = (int)CustomError.InvalidOperation;
                result.ErrMessage = "该数据已被别人修改,请重试！";
                result.Msg = "操作失败！";
            }
            else
            {
                logger.LogError(e, e.Message);
                result.Code = (int)CustomError.InvalidOperation;
                result.ErrMessage = "出错了,请稍后再试";
                result.Msg = "操作失败！";
            }
        }
    }
}
